{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# KNN or K-Nearest Neighbours"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "KNN is a lazy learning algorithm which is used for classification. In this algorithm, the unknown or test set data will consider 'K' nearest neighbours from training set and predict the class based on count of its 'K' nearest neighbours i.e Among it's K nearest neighbours, which ever class has the highest count, it will be assigned to that particular class. Steps involved in this algorithm are:\n",
    "\n",
    "1. Choose the number K of neighbours\n",
    "2. Take the K nearest neighbours of the new data point, according to Euclidian Distance\n",
    "3. Among the data points, count the number of datapoints in each category.\n",
    "4. Assign the new data point to the category where you counted the most neighbours."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# -*- coding: utf-8 -*-\n",
    "\"\"\"\n",
    "Created on Mon Nov 26 16:06:25 2018\n",
    "\n",
    "@author: purandur\n",
    "\"\"\"\n",
    "#imporing libraries\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import pandas as pd\n",
    "import time"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "#feature scaling\n",
    "class FeatureScaling:\n",
    "    def __init__(self,X,y):\n",
    "        self.X=X.copy()\n",
    "        if y.ndim==1:\n",
    "            y=np.reshape(y,(y.shape[0],1))\n",
    "        self.y=y.copy()\n",
    "        self.minMax_X={}\n",
    "        self.minMax_y={}\n",
    "    \n",
    "    def fit_transform_X(self):\n",
    "        num_of_features=self.X.shape[1]\n",
    "        for i in range(num_of_features):\n",
    "            feature=self.X[:,i]\n",
    "            Mean=np.mean(feature)\n",
    "            Min=np.min(feature)\n",
    "            Max=np.max(feature)\n",
    "            feature=(feature-Mean)/(Max-Min)\n",
    "            self.minMax_X[i]=np.array([Mean,Min,Max])\n",
    "            self.X[:,i]=feature\n",
    "        return self.X.copy()\n",
    "    \n",
    "    def fit_transform_Y(self):\n",
    "        num_of_features=self.y.shape[1]\n",
    "        for i in range(num_of_features):\n",
    "            feature=self.y[:,i]\n",
    "            Mean=np.mean(feature)\n",
    "            Min=np.min(feature)\n",
    "            Max=np.max(feature)\n",
    "            feature=(feature-Mean)/(Max-Min)\n",
    "            self.minMax_y[i]=np.array([Mean,Min,Max])\n",
    "            self.y[:,i]=feature\n",
    "        return np.reshape(self.y,self.y.shape[0])\n",
    "    \n",
    "    def inverse_transform_X(self,X):\n",
    "        X_transformed=X.copy()\n",
    "        num_of_features=X_transformed.shape[1]\n",
    "        for i in range(num_of_features):\n",
    "            feature=X_transformed[:,i]\n",
    "            Mean=self.minMax_X[i][0]\n",
    "            Min=self.minMax_X[i][1]\n",
    "            Max=self.minMax_X[i][2]\n",
    "            feature=feature*(Max-Min)+Mean\n",
    "            X_transformed[:,i]=feature\n",
    "        return X_transformed\n",
    "    \n",
    "    def inverse_transform_Y(self,y):\n",
    "        y_transformed=y.copy()\n",
    "        if y_transformed.ndim==1:\n",
    "            y_transformed=np.reshape(y_transformed,(y_transformed.shape[0],1))\n",
    "        num_of_features=y_transformed.shape[1]\n",
    "        for i in range(num_of_features):\n",
    "            feature=y_transformed[:,i]\n",
    "            Mean=self.minMax_y[i][0]\n",
    "            Min=self.minMax_y[i][1]\n",
    "            Max=self.minMax_y[i][2]\n",
    "            feature=feature*(Max-Min)+Mean\n",
    "            y_transformed[:,i]=feature\n",
    "        return np.reshape(y_transformed,y_transformed.shape[0])\n",
    "    \n",
    "    def transform_X(self,X):\n",
    "        X_transformed=X.copy()\n",
    "        num_of_features=X_transformed.shape[1]\n",
    "        for i in range(num_of_features):\n",
    "            feature=X_transformed[:,i]\n",
    "            Mean=self.minMax_X[i][0]\n",
    "            Min=self.minMax_y[i][1]\n",
    "            Max=self.minMax_y[i][2]\n",
    "            feature=(feature-Mean)/(Max-Min)\n",
    "            X_transformed[:,i]=feature\n",
    "        return X_transformed\n",
    "    \n",
    "    def transform_Y(self,y):\n",
    "        y_transformed=y.copy()\n",
    "        if y_transformed.ndim==1:\n",
    "            y_transformed=np.reshape(y_transformed,(y_transformed.shape[0],1))\n",
    "        num_of_features=y_transformed.shape[1]\n",
    "        for i in range(num_of_features):\n",
    "            feature=y_transformed[:,i]\n",
    "            Mean=self.minMax_y[i][0]\n",
    "            Min=self.minMax_y[i][1]\n",
    "            Max=self.minMax_y[i][2]\n",
    "            feature=(feature-Mean)/(Max-Min)\n",
    "            y_transformed[:,i]=feature\n",
    "        return np.reshape(y_transformed,y_transformed.shape[0])\n",
    "    \n",
    "    def returnX(self):\n",
    "        return self.X\n",
    "    \n",
    "    def returnY(self):\n",
    "        return self.y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "class KNN:\n",
    "    def __init__(self,X_train,Y_train,K):\n",
    "        self.X_train=X_train\n",
    "        self.Y_train=Y_train\n",
    "        self.K=K\n",
    "        \n",
    "    def predict(self,X):\n",
    "        y_pred=np.array([])\n",
    "        for each in X:\n",
    "            ed=np.sum((each-self.X_train)**2,axis=1)\n",
    "            y_ed=np.concatenate((self.Y_train.reshape(self.Y_train.shape[0],1),ed.reshape(ed.shape[0],1)),axis=1)\n",
    "            y_ed=y_ed[y_ed[:,1].argsort()]\n",
    "            K_neighbours=y_ed[0:self.K]\n",
    "            (values,counts) = np.unique(K_neighbours[:,0].astype(int),return_counts=True)\n",
    "            y_pred=np.append(y_pred,values[np.argmax(counts)])\n",
    "        return y_pred\n",
    "            "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "    User ID  Gender  Age  EstimatedSalary  Purchased\n",
      "0  15624510    Male   19            19000          0\n",
      "1  15810944    Male   35            20000          0\n",
      "2  15668575  Female   26            43000          0\n",
      "3  15603246  Female   27            57000          0\n",
      "4  15804002    Male   19            76000          0\n",
      "5  15728773    Male   27            58000          0\n",
      "6  15598044  Female   27            84000          0\n",
      "7  15694829  Female   32           150000          1\n",
      "8  15600575    Male   25            33000          0\n",
      "9  15727311  Female   35            65000          0\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>User ID</th>\n",
       "      <th>Age</th>\n",
       "      <th>EstimatedSalary</th>\n",
       "      <th>Purchased</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>count</th>\n",
       "      <td>4.000000e+02</td>\n",
       "      <td>400.000000</td>\n",
       "      <td>400.000000</td>\n",
       "      <td>400.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>mean</th>\n",
       "      <td>1.569154e+07</td>\n",
       "      <td>37.655000</td>\n",
       "      <td>69742.500000</td>\n",
       "      <td>0.357500</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>std</th>\n",
       "      <td>7.165832e+04</td>\n",
       "      <td>10.482877</td>\n",
       "      <td>34096.960282</td>\n",
       "      <td>0.479864</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>min</th>\n",
       "      <td>1.556669e+07</td>\n",
       "      <td>18.000000</td>\n",
       "      <td>15000.000000</td>\n",
       "      <td>0.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>25%</th>\n",
       "      <td>1.562676e+07</td>\n",
       "      <td>29.750000</td>\n",
       "      <td>43000.000000</td>\n",
       "      <td>0.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>50%</th>\n",
       "      <td>1.569434e+07</td>\n",
       "      <td>37.000000</td>\n",
       "      <td>70000.000000</td>\n",
       "      <td>0.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>75%</th>\n",
       "      <td>1.575036e+07</td>\n",
       "      <td>46.000000</td>\n",
       "      <td>88000.000000</td>\n",
       "      <td>1.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>max</th>\n",
       "      <td>1.581524e+07</td>\n",
       "      <td>60.000000</td>\n",
       "      <td>150000.000000</td>\n",
       "      <td>1.000000</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "            User ID         Age  EstimatedSalary   Purchased\n",
       "count  4.000000e+02  400.000000       400.000000  400.000000\n",
       "mean   1.569154e+07   37.655000     69742.500000    0.357500\n",
       "std    7.165832e+04   10.482877     34096.960282    0.479864\n",
       "min    1.556669e+07   18.000000     15000.000000    0.000000\n",
       "25%    1.562676e+07   29.750000     43000.000000    0.000000\n",
       "50%    1.569434e+07   37.000000     70000.000000    0.000000\n",
       "75%    1.575036e+07   46.000000     88000.000000    1.000000\n",
       "max    1.581524e+07   60.000000    150000.000000    1.000000"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#reading dataset\n",
    "Data=pd.read_csv('Social_Network_Ads.csv')\n",
    "print(Data.head(10))\n",
    "Data.describe()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Training set size : 300\n",
      "Testing set size : 100\n"
     ]
    }
   ],
   "source": [
    "#training and testing set size\n",
    "train_size=int(0.75*Data.shape[0])\n",
    "test_size=int(0.25*Data.shape[0])\n",
    "print(\"Training set size : \"+ str(train_size))\n",
    "print(\"Testing set size : \"+str(test_size))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Getting features from dataset\n",
    "Data=Data.sample(frac=1)\n",
    "X=Data.iloc[:,[2, 3]].values\n",
    "y=Data.iloc[:,4].values\n",
    "X=X.astype(float)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "#feature scaling\n",
    "fs=FeatureScaling(X,y)\n",
    "X=fs.fit_transform_X()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "#training set split\n",
    "X_train=X[0:train_size,:]\n",
    "Y_train=y[0:train_size]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "#testing set split\n",
    "X_test=X[train_size:,:]\n",
    "Y_test=y[train_size:]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.017045021057128906\n"
     ]
    }
   ],
   "source": [
    "l=time.time()\n",
    "knn=KNN(X_train,Y_train,5)\n",
    "y_pred=knn.predict(X_test)\n",
    "r=time.time()\n",
    "KNN_learn_time=(r-l)\n",
    "print(r-l)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[54  8]\n",
      " [ 6 32]]\n"
     ]
    }
   ],
   "source": [
    "#getting the confusion matrix\n",
    "tp=len([i for i in range(0,Y_test.shape[0]) if Y_test[i]==0 and y_pred[i]==0])\n",
    "tn=len([i for i in range(0,Y_test.shape[0]) if Y_test[i]==0 and y_pred[i]==1])\n",
    "fp=len([i for i in range(0,Y_test.shape[0]) if Y_test[i]==1 and y_pred[i]==0])\n",
    "fn=len([i for i in range(0,Y_test.shape[0]) if Y_test[i]==1 and y_pred[i]==1])\n",
    "confusion_matrix=np.array([[tp,tn],[fp,fn]])\n",
    "print(confusion_matrix)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.0020058155059814453\n"
     ]
    }
   ],
   "source": [
    "#Same algorithm using sklearn KNN just for comparsion purpose\n",
    "from sklearn.neighbors import KNeighborsClassifier\n",
    "classifier = KNeighborsClassifier(n_neighbors = 5, metric = 'minkowski', p = 2)\n",
    "l=time.time()\n",
    "classifier.fit(X_train, Y_train)\n",
    "y_pred_sklearn = classifier.predict(X_test)\n",
    "r=time.time()\n",
    "sklearn_time=(r-l)\n",
    "print(sklearn_time)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "But sklearn time is faster than our implementation by: 8.497801022227504 times\n"
     ]
    }
   ],
   "source": [
    "print(\"But sklearn time is faster than our implementation by: \"+str(KNN_learn_time/sklearn_time)+\" times\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[54  8]\n",
      " [ 6 32]]\n"
     ]
    }
   ],
   "source": [
    "# Making the Confusion Matrix\n",
    "from sklearn.metrics import confusion_matrix\n",
    "cm = confusion_matrix(Y_test, y_pred_sklearn)\n",
    "print(cm)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Time required for plotting is: 25.802637815475464 seconds\n"
     ]
    }
   ],
   "source": [
    "# Visualising the Training set results for our implementation\n",
    "l=time.time()\n",
    "from matplotlib.colors import ListedColormap\n",
    "X_set, y_set = X_train, Y_train\n",
    "X1, X2 = np.meshgrid(np.arange(start = X_set[:, 0].min() - 1, stop = X_set[:, 0].max() + 1, step = 0.01),\n",
    "                     np.arange(start = X_set[:, 1].min() - 1, stop = X_set[:, 1].max() + 1, step = 0.01))\n",
    "plt.contourf(X1, X2, knn.predict(np.array([X1.ravel(), X2.ravel()]).T).reshape(X1.shape),\n",
    "             alpha = 0.75, cmap = ListedColormap(('orange', 'green')))\n",
    "plt.xlim(X1.min(), X1.max())\n",
    "plt.ylim(X2.min(), X2.max())\n",
    "for i, j in enumerate(np.unique(y_set)):\n",
    "    plt.scatter(X_set[y_set == j, 0], X_set[y_set == j, 1],\n",
    "                c = ListedColormap(('red', 'green'))(i), label = j,marker='.')\n",
    "plt.title('K-NN (Training set) using our implementation')\n",
    "plt.xlabel('Age')\n",
    "plt.ylabel('Estimated Salary')\n",
    "plt.legend()\n",
    "plt.show()\n",
    "r=time.time()\n",
    "print(\"Time required for plotting is: \"+str(r-l)+\" seconds\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Time required for plotting is: 22.427660942077637 seconds\n"
     ]
    }
   ],
   "source": [
    "# Visualising the Test set results for our implementation\n",
    "l=time.time()\n",
    "X_set, y_set = X_test, Y_test\n",
    "X1, X2 = np.meshgrid(np.arange(start = X_set[:, 0].min() - 1, stop = X_set[:, 0].max() + 1, step = 0.01),\n",
    "                     np.arange(start = X_set[:, 1].min() - 1, stop = X_set[:, 1].max() + 1, step = 0.01))\n",
    "plt.contourf(X1, X2, knn.predict(np.array([X1.ravel(), X2.ravel()]).T).reshape(X1.shape),\n",
    "             alpha = 0.75, cmap = ListedColormap(('orange', 'green')))\n",
    "plt.xlim(X1.min(), X1.max())\n",
    "plt.ylim(X2.min(), X2.max())\n",
    "for i, j in enumerate(np.unique(y_set)):\n",
    "    plt.scatter(X_set[y_set == j, 0], X_set[y_set == j, 1],\n",
    "                c = ListedColormap(('red', 'green'))(i), label = j,marker='.')\n",
    "plt.title('K-NN (Test set) using our implementation')\n",
    "plt.xlabel('Age')\n",
    "plt.ylabel('Estimated Salary')\n",
    "plt.legend()\n",
    "plt.show()\n",
    "r=time.time()\n",
    "print(\"Time required for plotting is: \"+str(r-l)+\" seconds\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Time required for plotting is: 0.48911190032958984 seconds\n"
     ]
    }
   ],
   "source": [
    "# Visualising the Training set results for sklearn class\n",
    "l=time.time()\n",
    "X_set, y_set = X_train, Y_train\n",
    "X1, X2 = np.meshgrid(np.arange(start = X_set[:, 0].min() - 1, stop = X_set[:, 0].max() + 1, step = 0.01),\n",
    "                     np.arange(start = X_set[:, 1].min() - 1, stop = X_set[:, 1].max() + 1, step = 0.01))\n",
    "plt.contourf(X1, X2, classifier.predict(np.array([X1.ravel(), X2.ravel()]).T).reshape(X1.shape),\n",
    "             alpha = 0.75, cmap = ListedColormap(('orange', 'green')))\n",
    "plt.xlim(X1.min(), X1.max())\n",
    "plt.ylim(X2.min(), X2.max())\n",
    "for i, j in enumerate(np.unique(y_set)):\n",
    "    plt.scatter(X_set[y_set == j, 0], X_set[y_set == j, 1],\n",
    "                c = ListedColormap(('red', 'green'))(i), label = j,marker='.')\n",
    "plt.title('K-NN (Training set)')\n",
    "plt.xlabel('Age')\n",
    "plt.ylabel('Estimated Salary')\n",
    "plt.legend()\n",
    "plt.show()\n",
    "r=time.time()\n",
    "print(\"Time required for plotting is: \"+str(r-l)+\" seconds\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Time required for plotting is: 0.47005295753479004 seconds\n"
     ]
    }
   ],
   "source": [
    "# Visualising the Test set results for sklearn class\n",
    "l=time.time()\n",
    "X_set, y_set = X_test, Y_test\n",
    "X1, X2 = np.meshgrid(np.arange(start = X_set[:, 0].min() - 1, stop = X_set[:, 0].max() + 1, step = 0.01),\n",
    "                     np.arange(start = X_set[:, 1].min() - 1, stop = X_set[:, 1].max() + 1, step = 0.01))\n",
    "plt.contourf(X1, X2, classifier.predict(np.array([X1.ravel(), X2.ravel()]).T).reshape(X1.shape),\n",
    "             alpha = 0.75, cmap = ListedColormap(('orange', 'green')))\n",
    "plt.xlim(X1.min(), X1.max())\n",
    "plt.ylim(X2.min(), X2.max())\n",
    "for i, j in enumerate(np.unique(y_set)):\n",
    "    plt.scatter(X_set[y_set == j, 0], X_set[y_set == j, 1],\n",
    "                c = ListedColormap(('red', 'green'))(i), label = j,marker='.')\n",
    "plt.title('K-NN (Test set)')\n",
    "plt.xlabel('Age')\n",
    "plt.ylabel('Estimated Salary')\n",
    "plt.legend()\n",
    "plt.show()\n",
    "r=time.time()\n",
    "print(\"Time required for plotting is: \"+str(r-l)+\" seconds\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Conclusion is our implementation is slower but still we have achieved similar results compared to sklearn package"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
